//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using CommunityServer.Components;
using System.Web.Caching;

namespace CommunityServer.Components
{
    public class UsersOnline
    {
        #region cntr.
        private UsersOnline(){}
        #endregion

        #region Containers
        private Hashtable _guests = new Hashtable();
        private Hashtable _members = new Hashtable();

        internal ArrayList GetMembers
        {
            get 
			{ 
				string key = "OnlineUsers-" + CSContext.Current.SettingsID.ToString() + "-GetMembers";
				ArrayList members = CSCache.Get(key) as ArrayList;
				if (members == null)
				{
					lock(_members.SyncRoot)
					{
						members = CSCache.Get(key) as ArrayList;
						if (members == null)
						{
							members = new ArrayList(_members.Values);
							CSCache.Insert(key, members, (int) CSCache.SecondFactor * 30, CacheItemPriority.Normal);
						}
					}
				}

				return members;
			}
        }

        internal ArrayList GetGuests
        {
            get 
			{ 
				string key = "OnlineUsers-" + CSContext.Current.SettingsID.ToString() + "-GetGuests";
				ArrayList guests = CSCache.Get(key) as ArrayList;
				if (guests == null)
				{
					lock(_guests.SyncRoot)
					{
						guests = CSCache.Get(key) as ArrayList;
						if (guests == null)
						{
							guests = new ArrayList(_guests.Values);
							CSCache.Insert(key, guests, (int) CSCache.SecondFactor * 30, CacheItemPriority.Normal);
						}
					}
				}

				return guests;			
			}
        }
        #endregion

        #region Set User 

        private void Insert(UserOnline uo)
        {
            if(uo.User.IsAnonymous)
            {
                lock(_guests.SyncRoot)
                {
                    _guests[uo.AnonymousId] = uo;
                }
            }
            else
            {
                lock(_members.SyncRoot)
                {
                    _members[uo.UserID] = uo;
                }
            }
        }

        #endregion

        #region Clean Up

        private void MemberCleanUp(int minutes)
        {
            lock(_members.SyncRoot)
            {
                DateTime filter = DateTime.Now.AddMinutes( -1 * minutes);
                ArrayList al = new ArrayList(_members.Count);
                foreach(UserOnline user in _members.Values)
                {
                    if(user.LastActivity >= filter)
                    {
                        al.Add(user);
                    }
                }

                _members.Clear();
                foreach(UserOnline user in al)
                {
                    _members[user.UserID] = user;
                }
            }
        }

        private void GuestCleanUp(int minutes)
        {
            lock(_guests.SyncRoot)
            {
                DateTime filter = DateTime.Now.AddMinutes( -1 * minutes);
                ArrayList al = new ArrayList(_guests.Count);
                foreach(UserOnline user in _guests.Values)
                {
                    if(user.LastActivity >= filter)
                    {
                        al.Add(user);
                    }
                }

                _guests.Clear();
                foreach(UserOnline user in al)
                {
                    _guests[user.AnonymousId] = user;
                }
            }
        }

        #endregion

        #region Accessors

        public static ArrayList Members()
        {
            return Instance().GetMembers;
        }

        public static ArrayList Guests()
        {
            return Instance().GetGuests;
        }

        public static int GuestCount
        {
            get
			{ 
				return Instance()._guests.Count;
			}
        }

        public static int MemberCount
        {
            get
			{ 
				string key = "OnlineUsers-" + CSContext.Current.SettingsID.ToString() + "-MemberCount";

				return Instance()._members.Count;
			}
        }

        public static void PrivateLocation()
        {
            SetLocation(null,null);
        }

        public static void SetLocation(string location)
        {
            SetLocation(location,CSContext.Current.RawUrl);
        }

        public static void SetLocation(string location, string link)
        {
			CSContext cntx = CSContext.Current;
			if (cntx.Config.EnableUsersOnline)
			{
				
				UserOnline uo = null;
				if(cntx.IsAuthenticated)
				{
					uo = new UserOnline(cntx.User);
				}
				else if(cntx.SiteSettings.EnableAnonymousUserTracking)
				{
					uo = new UserOnline(cntx.User,cntx.AnonymousUserID);
				}

				if(uo != null)
				{
					if(location == null)
						location = ResourceManager.GetString("location_PrivateArea",true);

					uo.Location = location;
					uo.Link = link;

					Instance().Insert(uo);

				}
			}
        }

        public static void ClearMembers(int minutes)
        {
            Instance().MemberCleanUp(minutes);
        }

        public static void ClearGuests(int minutes)
        {
            Instance().GuestCleanUp(minutes);
        }

        #endregion

        #region Instance Manager

        private static UsersOnline Instance()
        {
            CSContext context = CSContext.Current;
            string key = "OnlineUsers-" + context.SettingsID.ToString();

            UsersOnline ou = CSCache.Get(key) as UsersOnline;
            if(ou == null)
            {
				lock(typeof(UsersOnline))
				{
					ou = CSCache.Get(key) as UsersOnline;
					if (ou == null)
					{
						ou = new UsersOnline();
						CSCache.Permanent(key,ou);
					}
				}
            }

            return ou;
        }

        #endregion

    }
}